package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.enums.AttendEnums;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.system.feign.SysUserFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class AttendGroupServiceImpl implements AttendGroupService {

    @Autowired
    private AttendGroupMapper attendGroupMapper;
    @Autowired
    private SysUserFeign sysUserFeign;
    @Autowired
    private AttendGroupPartMapper attendGroupPartMapper;

    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {

        //查询当前企业下考勤组的数量
        LambdaQueryWrapper<AttendGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        Integer count = attendGroupMapper.selectCount(wrapper);

        //如果没有, 需要新增默认考勤组
        if(count == 0) {
            AttendGroup attendGroup = buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);

            //将默认考勤组与企业的所有部门 , 关联起来 -----> 所有部门都采用这个考勤组 ======> at_attend_group_part
            //查询当前企业所有的部门ID
            List<Long> depIds = sysUserFeign.queryDepartmentIds().getData();

            //保存默认考勤组参数者
            if(CollectionUtil.isNotEmpty(depIds)){
                for (Long depId : depIds) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    attendGroupPart.setAttendGroupId(attendGroup.getId());//考勤组ID
                    attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());//参与
                    attendGroupPart.setObjectId(depId);
                    attendGroupPart.setObjectType(AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());

                    attendGroupPartMapper.insert(attendGroupPart);
                }
            }

        }


        //分页查询企业考勤组列表数据
        Page<AttendGroup> p = new Page<>(page, pageSize);
        p = attendGroupMapper.selectPage(p , wrapper);

        List<AttendGroup> attendGroupList = p.getRecords();

        List<AttendGroupDTO> groupDTOS = BeanHelper.copyWithCollection(attendGroupList, AttendGroupDTO.class);

        //遍历考勤组列表，获取企业考勤组中 -------> 参与者数量
        groupDTOS.stream().forEach(attendGroup -> {

            Long id = attendGroup.getId();//考勤组ID

            //组装条件查询考勤组的参与者列表
            LambdaQueryWrapper<AttendGroupPart> partWrapper = new LambdaQueryWrapper<>();
            partWrapper.eq(AttendGroupPart::getAttendGroupId, id);//考勤组ID
            partWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());

            List<AttendGroupPart> groupParts = attendGroupPartMapper.selectList(partWrapper);//参与者列表

            //获取参与者是部门的集合
            List<Long> depIds = new ArrayList<>();
            for (AttendGroupPart groupPart : groupParts) {
                if(groupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_DEP.value()){
                    depIds.add(groupPart.getObjectId());
                }
            }

            //stream流操作
            /*
            List<Long> idList = groupParts.stream().filter(attendGroupPart -> {
                return attendGroupPart.getObjectType() == 1;
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());
            */

            //获取参与者是用户的集合
            List<Long> userIds = new ArrayList<>();
            for (AttendGroupPart groupPart : groupParts) {
                if(groupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_USER.value()){
                    userIds.add(groupPart.getObjectId());
                }
            }

            //获取部门下的员工数量
            Integer depCount = sysUserFeign.queryUserCountByDepartmentIds(depIds).getData();

            //总员工数量
            Integer countNum = depCount + userIds.size();

            attendGroup.setMemberNum(countNum);
        });

        //组装数据返回
        return new PageResult<>(p.getTotal(), p.getPages(), groupDTOS);
    }




    //构建默认的考勤组
    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setAddressRange(500);//打卡范围
        attendGroup.setAllowLateMinutes(10);//允许迟到分数数
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());//企业ID
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());//创建人
        attendGroup.setCreateTime(new Date());//创建时间
        attendGroup.setUpdateUserId(CurrentUserHolder.get().getCompanyUserId());//更新人
        attendGroup.setUpdateTime(new Date());//更新时间

        attendGroup.setLat(new BigDecimal("116.37439200000000000000"));
        attendGroup.setLng(new BigDecimal("40.10492600000000000000"));
        attendGroup.setAddressName("七北路42号TBD云集中心2号楼3单元3层");
        attendGroup.setAddress("传智播客北京中心TBD校区");

        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setOffWorkTime("18:00:00");
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setLateMinutes(30);//超过30分钟就算旷工
        attendGroup.setWorkdays("1,1,1,1,1,0,0");

        return attendGroup;
    }


    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
        //1.参数校验
        if(attendGroupDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }


        //2. 组装数据, 保存考勤组 -----> at_attend_group
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        //2.1 设置考勤组关联的企业ID - 创建人ID - 更新人ID
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());
        attendGroup.setUpdateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setUpdateTime(new Date());
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());

        //2.2 设置工作日, 使用逗号 "," 分割
        List<String> workdays = attendGroupDTO.getWorkdays();
        attendGroup.setWorkdays(StrUtil.join(",", workdays)); // 1,1,1,1,1,1

        //2.3 设置必须/不用打卡的日期 ----> 获取出来之后使用逗号","拼接
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();

        if (CollectionUtil.isNotEmpty(extraConfig)) {
            List<String> nessaryList = new ArrayList<>();//必须
            List<String> unnessaryList = new ArrayList<>();//不需要

            for (AttendGroupPCExtraConfigDTO configDTO : extraConfig) {
                if(configDTO.getRequiredAttend() == 1){
                    nessaryList.add(DateTimeUtil.dateToStr(new Date(Long.valueOf(configDTO.getSetDate())), DateTimeUtil.TIME_FORMAT_2));
                }else{
                    unnessaryList.add(DateTimeUtil.dateToStr(new Date(Long.valueOf(configDTO.getSetDate())), DateTimeUtil.TIME_FORMAT_2));
                }
            }

            attendGroup.setNecessaryTimeList(StrUtil.join(",", nessaryList));
            attendGroup.setUnnecessaryTimeList(StrUtil.join(",", unnessaryList));
        }

        //2.4 保存考勤组
        attendGroupMapper.insert(attendGroup);



        //3. 保存考勤组的参与者信息 -----> at_attend_group_part
        //3.1 需要参与考勤组的对象处理
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();

        if(CollectionUtil.isNotEmpty(participates)) {
            for (AttendGroupPartDTO partDTO : participates) {
                //3.1.1 判断当前对象 是否加入到某个考勤组（要求 : 用户/部门 只能加入一个考勤组，如果设置新考勤组 删除旧的考勤组）
                LambdaQueryWrapper<AttendGroupPart> partWrapper = new LambdaQueryWrapper<>();
                partWrapper.eq(AttendGroupPart::getObjectId, partDTO.getObjectId());
                partWrapper.eq(AttendGroupPart::getObjectType, partDTO.getObjectType());
                partWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());

                Integer count = attendGroupPartMapper.selectCount(partWrapper);
                if(count > 0) {
                    //3.1.2 如果存在旧的考勤组, 需要删除旧考勤组
                    attendGroupPartMapper.delete(partWrapper);
                }

                //3.1.3 给用户/部门关联新的考勤组
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectId(partDTO.getObjectId());
                attendGroupPart.setObjectType(partDTO.getObjectType());
                attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }



        //3.2 不需要参与考勤组的对象 处理
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();

        //3.2.1 新增无需考勤组用户记录
        if(CollectionUtil.isNotEmpty(notParticipates)){
            for (AttendGroupPartDTO partDTO : notParticipates) {
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectId(partDTO.getObjectId());
                attendGroupPart.setObjectType(partDTO.getObjectType());
                attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_NO.value());

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }

    }


    @Override
    public AttendGroupDTO queryAttendGroup() {
        //获取系统用户ID
        Long userId = CurrentUserHolder.get().getId();

        //根据系统用户ID查询考勤组参与者信息 --------> at_attend_group_part
        LambdaQueryWrapper<AttendGroupPart> partWrapper = new LambdaQueryWrapper<>();
        partWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());
        partWrapper.eq(AttendGroupPart::getObjectId, userId);
        partWrapper.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_USER.value());

        AttendGroupPart part = attendGroupPartMapper.selectOne(partWrapper);

        //如果没有查询到考勤组
        if(part == null){
            //获取员工对象的上级部门ID对应的集合
            List<Long> depIds = sysUserFeign.queryDepartmentsByUserId(CurrentUserHolder.get().getCompanyUserId()).getData();
            for (Long depId : depIds) {
                //获取部门对应的考勤组参与者信息
                LambdaQueryWrapper<AttendGroupPart> partWrapper1 = new LambdaQueryWrapper<>();
                partWrapper1.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());
                partWrapper1.eq(AttendGroupPart::getObjectId, depId);
                partWrapper1.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());

                part = attendGroupPartMapper.selectOne(partWrapper1);

                if(part != null){
                    break;
                }
            }
        }

        if(part == null){
            throw new NcException(ResponseEnum.USER_NOT_MATCH_ATTENDGROUP);
        }


        //查询考勤组数据, 组装, 返回
        AttendGroup attendGroup = attendGroupMapper.selectById(part.getAttendGroupId());
        AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);

        String workdays = attendGroup.getWorkdays();
        if(StrUtil.isNotEmpty(workdays)){
            attendGroupDTO.setWorkdays(Arrays.asList(workdays.split(",")));
        }

        return attendGroupDTO;
    }
}
